#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include "icpop.h"
#include "arguments.h"
#include "hangup.h"
#include <errno.h>
typedef struct {
	char * type_s;
	int type_i;
	char * ip_s;
	unsigned int port;
	int fd_sock;
	struct hostent *host;
	struct sockaddr_in server_addr;
		
	char * pipename_s;
	int fd_pipe;
	
	int epoll_fd;

} ICPOP_S;

int make_connect_to_host( ICPOP_S * icpop_p ){
	
	if( (icpop_p->host = gethostbyname( icpop_p->ip_s )) == NULL ){
		return -1;
	}
	
	icpop_p->server_addr.sin_family=AF_INET;
	icpop_p->server_addr.sin_port=htons(icpop_p->port);
	icpop_p->server_addr.sin_addr=*((struct in_addr *)icpop_p->host->h_addr);

	icpop_p->fd_sock = socket( PF_INET , icpop_p->type_i , 0 );
	if( icpop_p->fd_sock < 0 ){
		return -1;
	}
	
	if( connect( icpop_p->fd_sock ,
		(struct sockaddr *)(&icpop_p->server_addr),
		sizeof(struct sockaddr) )==-1 ){ 
		printf("Connect Error:%s\a\n",strerror(errno)); 
		return -1;	
	}
	return 0;
}

int make_pipe_to_user( ICPOP_S * icpop_p ){
	struct stat buf;	
	if( stat( icpop_p->pipename_s ,  &buf ) < 0 ){
		if( ENOENT == errno ){
			if( mkfifo( icpop_p->pipename_s,O_CREAT|O_RDWR ) < 0 ){
				return -1;
			}
		}else{
			return -1;
		}
	}

	icpop_p->fd_pipe = open( icpop_p->pipename_s , O_RDWR );
	if( icpop_p->fd_pipe<0 ){
		return -1;
	}
	return 0;
}
void set_nonblocking(int fd)
{
	int opts;
	opts=fcntl(fd, F_GETFL);
	if (opts < 0)
	{
		perror("fcntl failed\n");
		return;
	}
	opts = opts | O_NONBLOCK;
	if(fcntl(fd, F_SETFL, opts) < 0)
	{
		perror("fcntl failed\n");
		return;
	}
	return;
}

int loop_func( int arg_int , void * arg_p ){

	ICPOP_S icpop;
	icpop.type_s = my_opts[ARG_TYPE].ret_value.content.content_string;

	if( !strcasecmp( "tcp" , icpop.type_s ) ){
		icpop.type_i = SOCK_STREAM; 
	}else if( !strcasecmp( "udp" , icpop.type_s ) ){
		icpop.type_i = SOCK_DGRAM; 
	}else{
		return -1;
	}

	icpop.ip_s  = my_opts[ARG_HOST].ret_value.content.content_string;
	icpop.port  = my_opts[ARG_PORT].ret_value.content.content_int;
	icpop.pipename_s = my_opts[ARG_FILE].ret_value.content.content_string;

	if( make_pipe_to_user( &icpop) < 0 ){
		goto clearup;
	}
	if( make_connect_to_host( &icpop ) < 0 ){
		goto clearup;
	}
/***********************************************/
	char buf[25600];

	int nfds ,n;
	icpop.epoll_fd = epoll_create( 20 );
	struct epoll_event ev, events[10];
	ev.events = EPOLLIN | EPOLLET;
	set_nonblocking(icpop.fd_sock);
	ev.data.fd = icpop.fd_sock;
	epoll_ctl( icpop.epoll_fd , EPOLL_CTL_ADD , icpop.fd_sock , &ev );
	ev.events = EPOLLIN | EPOLLET;
	set_nonblocking(icpop.fd_pipe);
	ev.data.fd = icpop.fd_pipe;
	epoll_ctl( icpop.epoll_fd , EPOLL_CTL_ADD , icpop.fd_pipe , &ev );
 
	for(;;) {
		nfds = epoll_wait(icpop.epoll_fd , events, 20 , -1 );

		for(n = 0; n < nfds; ++n) {
			if(events[n].data.fd == icpop.fd_pipe ) {
				printf("events pipe:0x%X\n" , events[n].events );
				if( events[n].events & EPOLLHUP){
					printf("the other end close()\n");
					goto clearup;
				}
				memset(buf, 0 , 25600 );
				int len = read( icpop.fd_pipe , buf , 25600 );
				if( len >0 && !strcasecmp( buf , "open") ){
					printf("input open\n");
					snprintf( buf , 25600 , "GET / HTTP/1.1\r\nAccept: */*\r\nAccept-Language: zh-cn\r\nAccept-Encoding: gzip, deflate\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Foxy/1; Foxy/1)\r\nHost: 10.0.1.10\r\nConnection: Keep-Alive\r\n\r\n" );
					int len = write( icpop.fd_sock , buf , strlen(buf) );
					if( len < 0 ){
						perror("write failed");
						exit(1);
					}
				}
			}else if( events[n].data.fd = icpop.fd_sock ){
				printf("events sock:0x%X\n" , events[n].events );
/*				if( events[n].events & EPOLLHUP){
					printf("the other end close()\n");
					goto clearup;
				}
*/
				while( errno != EAGAIN ){
					memset(buf , 0 , 25600 );
					int len = read( icpop.fd_sock , buf  , 25600 );
					
					if( 0 == len  ){
						printf("other end close%d\n" , len );	
						goto clearup;
					}else if ( len < 0 ){
						printf( "nothing to read\n");
					}
//					write( icpop.fd_pipe , buf , len );
//					printf("%s" , buf );
					printf("len:%d\n" , len );
				}
			}
			ev.data.fd = events[n].data.fd;
			ev.events = EPOLLIN | EPOLLET;
			epoll_ctl( icpop.epoll_fd , EPOLL_CTL_ADD , ev.data.fd , &ev );
		}
	}

/************************************************/

clearup:
	if( icpop.fd_sock >=0 ){
		close(icpop.fd_sock);
		icpop.fd_sock = -1;
	}

	if( icpop.fd_pipe >=0 ){
		close( icpop.fd_pipe );
		icpop.fd_pipe = -1;
	}

	return 0;	
}

int main( int argc ,char ** argv ){
	int i;
	if( !handle_opts( argc , argv , my_opts , my_opts_count )){
		printf("handle_opts failed\n");
		for(i=0;i<my_opts_count ; i++ ){
			print_args(my_opts[i]);
		}	
		return -1;
	}
	char str[1000];
	snprintf( str , 1000 , "%s|%s|%d|%s" , 
				my_opts[ARG_TYPE].ret_value.content.content_string , 
				my_opts[ARG_HOST].ret_value.content.content_string , 
				my_opts[ARG_PORT].ret_value.content.content_int,
				my_opts[ARG_FILE].ret_value.content.content_string );

//	hangup( loop_func , my_opts[ARG_PORT].ret_value.content.content_int , str );
	loop_func( my_opts[ARG_PORT].ret_value.content.content_int , str );
	return 0;
}
